{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "basic_classification.ipynb",
      "version": "0.3.2",
      "provenance": [],
      "private_outputs": true,
      "collapsed_sections": [],
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    }
  },
  "cells": [
    {
      "metadata": {
        "colab_type": "text",
        "id": "MhoQ0WE77laV"
      },
      "cell_type": "markdown",
      "source": [
        "##### Copyright 2018 The TensorFlow Authors."
      ]
    },
    {
      "metadata": {
        "cellView": "form",
        "colab_type": "code",
        "id": "_ckMIh7O7s6D",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "cellView": "form",
        "colab_type": "code",
        "id": "vasWnqRgy1H4",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "#@title MIT License\n",
        "#\n",
        "# Copyright (c) 2017 François Chollet\n",
        "#\n",
        "# Permission is hereby granted, free of charge, to any person obtaining a\n",
        "# copy of this software and associated documentation files (the \"Software\"),\n",
        "# to deal in the Software without restriction, including without limitation\n",
        "# the rights to use, copy, modify, merge, publish, distribute, sublicense,\n",
        "# and/or sell copies of the Software, and to permit persons to whom the\n",
        "# Software is furnished to do so, subject to the following conditions:\n",
        "#\n",
        "# The above copyright notice and this permission notice shall be included in\n",
        "# all copies or substantial portions of the Software.\n",
        "#\n",
        "# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n",
        "# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n",
        "# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n",
        "# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n",
        "# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n",
        "# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n",
        "# DEALINGS IN THE SOFTWARE."
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "jYysdyb-CaWM"
      },
      "cell_type": "markdown",
      "source": [
        "# Обучи свою первую нейросеть: простой классификатор"
      ]
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "S5Uhzt6vVIB2"
      },
      "cell_type": "markdown",
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/tutorials/keras/basic_classification\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />Читай на TensorFlow.org</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs/blob/master/site/ru/tutorials/keras/basic_classification.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Запусти в Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs/blob/master/site/ru/tutorials/keras/basic_classification.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />Изучай код на GitHub</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "metadata": {
        "id": "5XyKqZetddAy",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        "Note: Вся информация в этом разделе переведена с помощью русскоговорящего Tensorflow сообщества на общественных началах. Поскольку этот перевод не является официальным, мы не гарантируем что он на 100% аккуратен и соответствует [официальной документации на английском языке](https://www.tensorflow.org/?hl=en). Если у вас есть предложение как исправить этот перевод, мы будем очень рады увидеть pull request в [tensorflow/docs](https://github.com/tensorflow/docs) репозиторий GitHub. Если вы хотите помочь сделать документацию по Tensorflow лучше (сделать сам перевод или проверить перевод подготовленный кем-то другим), напишите нам на [docs-ru@tensorflow.org list](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs-ru)."
      ]
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "FbVhjPpzn6BM"
      },
      "cell_type": "markdown",
      "source": [
        "Это пошаговое руководство поможет тебе обучить свою первую нейросеть, которая будет классифицировать картинки предметов одежды.\n",
        "\n",
        "Ничего страшного, если не все будет понятно сразу: это быстрый, ознакомительный обзор TensorFlow, где новые детали объясняются по мере их появления.\n",
        "\n",
        "В уроке используется [tf.keras](https://www.tensorflow.org/guide/keras), высокоуровневый Keras API для построения и обучения моделей в TensorFlow."
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "dzLKpmZICaWN",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "from __future__ import absolute_import, division, print_function, unicode_literals, unicode_literals\n",
        "\n",
        "# Импортируем TensorFlow и tf.keras\n",
        "import tensorflow as tf\n",
        "from tensorflow import keras\n",
        "\n",
        "# А также добавим вспомогательные библиотеки для вычислений и вывода данных на экран\n",
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "print(tf.__version__)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "yR0EdgrLCaWR"
      },
      "cell_type": "markdown",
      "source": [
        "## Загружаем Fashion MNIST датасет"
      ]
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "DLdCchMdCaWQ"
      },
      "cell_type": "markdown",
      "source": [
        "Мы будем использовать [Fashion MNIST](https://github.com/zalandoresearch/fashion-mnist) датасет, который состоит из 70,000 черно-белых изображений в 10 категориях. На каждом изображении по одному предмету одежды в низком разрешении (28 на 28 пикселей):\n",
        "\n",
        "<table>\n",
        "  <tr><td>\n",
        "    <img src=\"https://tensorflow.org/images/fashion-mnist-sprite.png\"\n",
        "         alt=\"Fashion MNIST sprite\"  width=\"600\">\n",
        "  </td></tr>\n",
        "  <tr><td align=\"center\">\n",
        "    <b>Рис. 1.</b> <a href=\"https://github.com/zalandoresearch/fashion-mnist\">Образцы Fashion-MNIST</a> (Zalando, лицензия MIT).<br/>&nbsp;\n",
        "  </td></tr>\n",
        "</table>\n",
        "\n",
        "Fashion MNIST составлялся как замена классическому [MNIST](http://yann.lecun.com/exdb/mnist/) датасету, который часто используют на первых уроках в программах по компьютерному зрению - своебразный \"Hello, World\" в мире машинного обучения. Классический датасет MNIST состоит из изображений рукописных чисел (0, 1, 2 и так далее) в точно таком же формате, как и предметы одежды, которыми мы будем пользоваться сегодня.\n",
        "\n",
        "Для разнообразия сегодня мы будем ипользовать Fashion MNIST, а также потому, что он представляет большую сложность в сравнении с MNIST. Оба датасета относительно малы, и нужны для проверки правильно ли работает алгоритм или нет. Их удобно использовать как отправные точки для тестирования и отладки кода.\n",
        "\n",
        "Чтобы обучить модель мы потренируем нейросеть на 60,000 изображений, а также загрузим еще 10,000 чтобы проверить, насколько правильно нейросеть обучилась предсказывать их класс. Ты можешь загрузить Fashion MNIST прямо в TensorFlow, просто сделай импорт и загрузи картинки:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "7MqDQO0KCaWS",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "fashion_mnist = keras.datasets.fashion_mnist\n",
        "\n",
        "(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "t9FDsUlxCaWW"
      },
      "cell_type": "markdown",
      "source": [
        "Загрузка датасета возвращает 4 массива NumPy:\n",
        "\n",
        "* Массивы `train_images` и `train_labels` являются *тренировочным сетом* — данными, на которых модель будет обучаться\n",
        "* Модель тестируется на *проверочном сете* - против массивов `test_images` и `test_labels`\n",
        "\n",
        "Изображения являются 28х28 массивами NumPy, где значение пикселей варьируется от 0 до 255. В столбике *Label* (далее - классы) содержится массив целых чисел от 0 до 9. Они соответствуют классу одежды, которые изображены на картинках:\n",
        "\n",
        "<table>\n",
        "  <tr>\n",
        "    <th>Label</th>\n",
        "    <th>Class</th>\n",
        "  </tr>\n",
        "  <tr>\n",
        "    <td>0</td>\n",
        "    <td>T-shirt/top</td>\n",
        "  </tr>\n",
        "  <tr>\n",
        "    <td>1</td>\n",
        "    <td>Trouser</td>\n",
        "  </tr>\n",
        "    <tr>\n",
        "    <td>2</td>\n",
        "    <td>Pullover</td>\n",
        "  </tr>\n",
        "    <tr>\n",
        "    <td>3</td>\n",
        "    <td>Dress</td>\n",
        "  </tr>\n",
        "    <tr>\n",
        "    <td>4</td>\n",
        "    <td>Coat</td>\n",
        "  </tr>\n",
        "    <tr>\n",
        "    <td>5</td>\n",
        "    <td>Sandal</td>\n",
        "  </tr>\n",
        "    <tr>\n",
        "    <td>6</td>\n",
        "    <td>Shirt</td>\n",
        "  </tr>\n",
        "    <tr>\n",
        "    <td>7</td>\n",
        "    <td>Sneaker</td>\n",
        "  </tr>\n",
        "    <tr>\n",
        "    <td>8</td>\n",
        "    <td>Bag</td>\n",
        "  </tr>\n",
        "    <tr>\n",
        "    <td>9</td>\n",
        "    <td>Ankle boot</td>\n",
        "  </tr>\n",
        "</table>\n",
        "\n",
        "Каждому изображению соответствует всего один класс одежды. Так как *названия классов* не включены в датасет, мы сохраним их здесь, чтобы позже использовать для вывода изображений с указанием категорий одежды:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "IjnLH5S2CaWx",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',\n",
        "               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "Brm0b_KACaWX"
      },
      "cell_type": "markdown",
      "source": [
        "## Изучаем данные\n",
        "\n",
        "Давай посмотрим на формат данных в датасете прежде, чем начнем тренировать модель. При помощи *shape* мы видим, что датасет состоит из 60,000 изображений размером 28 х 28 пикселей:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "zW5k_xz1CaWX",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "train_images.shape"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "cIAcvQqMCaWf"
      },
      "cell_type": "markdown",
      "source": [
        "Также мы видим, что в тренировочном сете всего 60,000 меток, по одной на каждое изображение:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "TRFYHB2mCaWb",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "len(train_labels)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "YSlYxFuRCaWk"
      },
      "cell_type": "markdown",
      "source": [
        "Каждая метка - это целое число от 0 до 9:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "XKnCTHz4CaWg",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "train_labels"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "TMPI88iZpO2T"
      },
      "cell_type": "markdown",
      "source": [
        "Проверочный сет содержит 10,000 изображений, каждое - также 28 на 28 пикселей:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "2KFnYlcwCaWl",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "test_images.shape"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "rd0A0Iu0CaWq"
      },
      "cell_type": "markdown",
      "source": [
        "И в проверочном сете - ровно 10,000 меток:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "iJmPr5-ACaWn",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "len(test_labels)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "ES6uQoLKCaWr"
      },
      "cell_type": "markdown",
      "source": [
        "## Подготовка данных к обучению модели\n",
        "\n",
        "Все данные должны быть подготовлены и обработаны одинаково перед обучением нейросети. Если мы посмотрим на первое изображение в тренировочном сете мы увидим, что значение пикселей находится в диапазоне от 0 до 255:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "m4VEw8Ud9Quh",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "plt.figure()\n",
        "plt.imshow(train_images[0])\n",
        "plt.colorbar()\n",
        "plt.grid(False)\n",
        "plt.show()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "Wz7l27Lz9S1P"
      },
      "cell_type": "markdown",
      "source": [
        "Мы должны машстабировать эти значения к диапазону от 0 до 1 прежде, чем обучать нейронную сеть. Для этого переведем тип данных изображений из целых в числа с плавающей запятой, и разделим на 255.\n",
        "\n",
        "Важно, чтобы и тренировочный, и проверочный сет были подготовлены одинаково."
      ]
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "3jCZdQNNCaWv"
      },
      "cell_type": "markdown",
      "source": [
        "Так будет выглядеть функция чтобы подготовить все изображения:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "bW5WzIPlCaWv",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "train_images = train_images / 255.0\n",
        "\n",
        "test_images = test_images / 255.0"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "Ee638AlnCaWz"
      },
      "cell_type": "markdown",
      "source": [
        "Выведем на экран первые 25 изображений из тренировочного сета и отобразим класс (Label) под каждым. Таким образом мы убедимся, что наши данные в правильном формате и готовы для построения и обучения нейросети."
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "oZTImqg_CaW1",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "plt.figure(figsize=(10,10))\n",
        "for i in range(25):\n",
        "    plt.subplot(5,5,i+1)\n",
        "    plt.xticks([])\n",
        "    plt.yticks([])\n",
        "    plt.grid(False)\n",
        "    plt.imshow(train_images[i], cmap=plt.cm.binary)\n",
        "    plt.xlabel(class_names[train_labels[i]])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "59veuiEZCaW4"
      },
      "cell_type": "markdown",
      "source": [
        "## Строим модель\n",
        "\n",
        "Построение модели нейронной сети требует правильной конфигурации каждого слоя, и последующей компиляции модели."
      ]
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "Gxg1XGm0eOBy"
      },
      "cell_type": "markdown",
      "source": [
        "### Создаем слои\n",
        "\n",
        "Базовым строительным блоком нейронной сети является *слой*. Слои извлекают точные представления из данных, на которых их обучают. И, конечно, будем надеяться, что в конечном итоге они извлекут что-то полезное для наших практических задач.\n",
        "\n",
        "Большинство моделей глубокого обучения состоят из простых слоев в цепочке. Большинство слоев, таких как `tf.keras.layers.Dense`, имеют параметры, которые используются в процессе тренировки:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "9ODch-OFCaW4",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "model = keras.Sequential([\n",
        "    keras.layers.Flatten(input_shape=(28, 28)),\n",
        "    keras.layers.Dense(128, activation=tf.nn.relu),\n",
        "    keras.layers.Dense(10, activation=tf.nn.softmax)\n",
        "])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "gut8A_7rCaW6"
      },
      "cell_type": "markdown",
      "source": [
        "Первый слой в нашей нейронной сети - `tf.keras.layers.Flatten` (flatten, пер. \"Выравнивать\"), преобразует изображения из двумерного массива (28 x 28 пикселей), в одномерный, размерностью 28 * 28 = 784 пикселей. Представь, что в этом слое мы как будто разбираем ряды сложенных пикселей изображения и выкладываем их в ряд. Этот слой не имеет никаких параметров для обучения; он просто преобразует формат данных.\n",
        "\n",
        "После того, как мы разложили все пиксели, нейросеть будет состоять из двух Dense (пер. \"Плотный\") `tf.keras.layers.Dense` слоев. Это так называемые полносвязные слои. Первый `Dense` слой состоит из 128 узлов, или нейронов. Второй и последний 10-и узловой *softmax* слой — возвращает массив из 10 вероятностных оценок, сумма которых равняется 1. Каждый нейрон содержит оценку, которая указывает вероятность принадлежности изображения к одному из 10 классов.\n",
        "\n",
        "### Компилируем модель\n",
        "\n",
        "Прежде чем модель будет готова для обучения, нам нужно указать еще несколько параметров. Их необходимо добавить в блоке *compile*:\n",
        "\n",
        "* *Loss function* (пер. \"Функция потерь\") — измеряет точность модели во время обучения. Мы хотим минимизировать значение этой функции, чтобы \\\"направить\\\" модель в нужном направлении\n",
        "\n",
        "* *Optimizer* — показывает каким образом обновляется модель на основе входных данных и функции потерь\n",
        "\n",
        "* *Metrics* — показывают шаги тренировки и тестирования модели. В нашем примере мы будем использовать *accuracy*, т.е. процент изображений, которые были классифицированы правильно"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "Lhan11blCaW7",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "model.compile(optimizer=tf.train.AdamOptimizer(),\n",
        "              loss='sparse_categorical_crossentropy',\n",
        "              metrics=['accuracy'])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "qKF6uW-BCaW-"
      },
      "cell_type": "markdown",
      "source": [
        "## Обучение модели\n",
        "\n",
        "Обучение модели нейронной сети требует выполнения следующих шагов:\n",
        "\n",
        "1. Загрузить тренировочные данные в модель, в нашем случае - массивами `train_images` и `train_labels`\n",
        "2. Модель учится ассоциировать изображения с правильными классами\n",
        "3. Мы запрашиваем модель предсказать классы одежды из проверочного сета `test_images`. Мы проверяем, соответствуют ли предсказанные классы меткам из массива `test_labels`.\n",
        "\n",
        "Чтобы начать обучение, вызови метод `model.fit` (fit, пер. \"Приспосабливать\", \"Вмещать\") - модель начнет обучаться на тренировочных данных:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "xvwvpA64CaW_",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "model.fit(train_images, train_labels, epochs=5)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "W3ZVOhugCaXA"
      },
      "cell_type": "markdown",
      "source": [
        "В процессе обучения модели отображаются показатели потери (*loss*) и точности (*acc*). В итоге модель достигает точности приблизительно 0.88 (88%), обучаясь на тренировочном сете."
      ]
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "oEw4bZgGCaXB"
      },
      "cell_type": "markdown",
      "source": [
        "## Оцениваем точность\n",
        "\n",
        "Далее, сравним какую точность модель покажет на проверчном датасете:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "VflXLEeECaXC",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "test_loss, test_acc = model.evaluate(test_images, test_labels)\n",
        "\n",
        "print('Точность после проверки:', test_acc)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "yWfgsmVXCaXG"
      },
      "cell_type": "markdown",
      "source": [
        "Полученная на проверчном сете точность оказалась немного ниже, чем на тренировочном. Этот разрыв между точностью на тренировке и тесте является примером *overfitting* (пер. \"Переобучение\"). Переобучение как правило возникает, когда модель машинного обучения показывает результат хуже на новых данных, чем на тех, на которых она обучалась."
      ]
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "xsoS7CPDCaXH"
      },
      "cell_type": "markdown",
      "source": [
        "## Получим предсказания\n",
        "\n",
        "Теперь, когда модель обучена, мы можем попробовать получить предсказания классов одежды на основе новых изображений:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "Gl91RPhdCaXI",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "predictions = model.predict(test_images)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "x9Kk1voUCaXJ"
      },
      "cell_type": "markdown",
      "source": [
        "Здесь полученная модель предсказала класс одежды для каждого изображения в проверчном датасете. Давай посмотрим на первое предсказание:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "3DmJEUinCaXK",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "predictions[0]"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "-hw1hgeSCaXN"
      },
      "cell_type": "markdown",
      "source": [
        "Предсказание класса представляет из себя массив из 10 чисел. Они описывают \"уверенность\" (*confidence*) соответствия изображения каждому из 10 разных предметов одежды. При помощи `np.argmax` мы можем увидеть какой метке соответствует максимальное значение уверенности:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "qsqenuPnCaXO",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "np.argmax(predictions[0])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "E51yS7iCCaXO"
      },
      "cell_type": "markdown",
      "source": [
        "Обученная модель полагает, что на первой картинке изображен бамшмак (ankle boot), или `class_names[9]`. И мы можем проверить, правильно ли это или нет:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "Sd7Pgsu6CaXP",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "test_labels[0]"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "ygh2yYC972ne"
      },
      "cell_type": "markdown",
      "source": [
        "Давай напишем вспомогательную функцию для быстрого построения диаграмм и посмотрим, как выглядят предсказания:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "DvYmmrpIy6Y1",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "def plot_image(i, predictions_array, true_label, img):\n",
        "  predictions_array, true_label, img = predictions_array[i], true_label[i], img[i]\n",
        "  plt.grid(False)\n",
        "  plt.xticks([])\n",
        "  plt.yticks([])\n",
        "\n",
        "  plt.imshow(img, cmap=plt.cm.binary)\n",
        "\n",
        "  predicted_label = np.argmax(predictions_array)\n",
        "  if predicted_label == true_label:\n",
        "    color = 'blue'\n",
        "  else:\n",
        "    color = 'red'\n",
        "\n",
        "  plt.xlabel(\"{} {:2.0f}% ({})\".format(class_names[predicted_label],\n",
        "                                100*np.max(predictions_array),\n",
        "                                class_names[true_label]),\n",
        "                                color=color)\n",
        "\n",
        "def plot_value_array(i, predictions_array, true_label):\n",
        "  predictions_array, true_label = predictions_array[i], true_label[i]\n",
        "  plt.grid(False)\n",
        "  plt.xticks([])\n",
        "  plt.yticks([])\n",
        "  thisplot = plt.bar(range(10), predictions_array, color=\"#777777\")\n",
        "  plt.ylim([0, 1])\n",
        "  predicted_label = np.argmax(predictions_array)\n",
        "\n",
        "  thisplot[predicted_label].set_color('red')\n",
        "  thisplot[true_label].set_color('blue')"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "d4Ov9OFDMmOD"
      },
      "cell_type": "markdown",
      "source": [
        "Теперь посмотрим на самое первое изображение (0), финальное предсказание и массив вероятностей, используя нашу новую функцию:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "HV5jw-5HwSmO",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "i = 0\n",
        "plt.figure(figsize=(6,3))\n",
        "plt.subplot(1,2,1)\n",
        "plot_image(i, predictions, test_labels, test_images)\n",
        "plt.subplot(1,2,2)\n",
        "plot_value_array(i, predictions,  test_labels)\n",
        "plt.show()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "QipmujfAdbPG",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        "Для сравнения посмотрим на другое изображение (12):"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "Ko-uzOufSCSe",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "i = 12\n",
        "plt.figure(figsize=(6,3))\n",
        "plt.subplot(1,2,1)\n",
        "plot_image(i, predictions, test_labels, test_images)\n",
        "plt.subplot(1,2,2)\n",
        "plot_value_array(i, predictions,  test_labels)\n",
        "plt.show()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "kgdvGD52CaXR"
      },
      "cell_type": "markdown",
      "source": [
        "Теперь давай отобразим несколько изображений и их предсказанные классы:\n",
        "\n",
        "1. Правильные предсказания будут отмечены синим, неправильные - красным\n",
        "2. Также мы укажем процент правильности предсказания метки изображения\n",
        "\n",
        "Обрати внимание:\n",
        "\n",
        "Предсказания могут быть неправильными, даже если модель уверена что все верно!"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "hQlnbqaw2Qu_",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "# Отображаем первые X тестовых изображений, их предсказанную и настоящую метки\n",
        "# Корректные предсказания окрашиваем в синий цвет, ошибочные в красный\n",
        "num_rows = 5\n",
        "num_cols = 3\n",
        "num_images = num_rows*num_cols\n",
        "plt.figure(figsize=(2*2*num_cols, 2*num_rows))\n",
        "for i in range(num_images):\n",
        "  plt.subplot(num_rows, 2*num_cols, 2*i+1)\n",
        "  plot_image(i, predictions, test_labels, test_images)\n",
        "  plt.subplot(num_rows, 2*num_cols, 2*i+2)\n",
        "  plot_value_array(i, predictions, test_labels)\n",
        "plt.show()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "R32zteKHCaXT"
      },
      "cell_type": "markdown",
      "source": [
        "Наконец, используем обученную модель для предсказания класса на одном изображении:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "yRJ7JU7JCaXT",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "# Берем одну картинку из проверочного сета\n",
        "img = test_images[0]\n",
        "\n",
        "print(img.shape)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "vz3bVp21CaXV"
      },
      "cell_type": "markdown",
      "source": [
        "Модели `tf.keras` оптимизированы делать предсказания на *batch* (пер. \"Пакетах данных\"), или на множестве примеров сразу. Таким образом, даже если мы используем всего 1 картинку, нам все равно необходимо добавить ее в список:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "lDFh5yF_CaXW",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "# Добавляем изображение в наш пакет данных, состоящий только из одного нашего изображения\n",
        "img = (np.expand_dims(img,0))\n",
        "\n",
        "print(img.shape)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "EQ5wLTkcCaXY"
      },
      "cell_type": "markdown",
      "source": [
        "И предсказываем класс этого изображения:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "o_rzNSdrCaXY",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "predictions_single = model.predict(img)\n",
        "\n",
        "print(predictions_single)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "GChNz2MqdbPb",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        "Выводим на экран диаграмму:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "6Ai-cpLjO-3A",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "plot_value_array(0, predictions_single, test_labels)\n",
        "_ = plt.xticks(range(10), class_names, rotation=45)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "cU1Y2OAMCaXb"
      },
      "cell_type": "markdown",
      "source": [
        "Метод `model.predict` возвращает нам список списков, один для каждой картинки в пакете данных.\n",
        "\n",
        "При помощи `np.argmax` давай оставим предсказание с максимальной вероятностью для нашей картинки:"
      ]
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "2tRmdq_8CaXb",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "np.argmax(predictions_single[0])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "YFc2HbEVCaXd"
      },
      "cell_type": "markdown",
      "source": [
        "И, как и в первый раз, модель предсказывает нам класс 9 - это башмак!"
      ]
    }
  ]
}
